export namespace cangjie {

export const enum SyntaxKind {
    Argument,
    Annotation,
    ArrayLiteral,
    AsExpr,
    AssignExpr,
    BinaryExpr,
    Block,
    Body,
    GenericConstraint, ////////////
    GenericParam, ///////////
    CallExpr,
    ClassDecl,
    ConstPattern,
    LitConstExpr, ////////////////
    Constructor,
    DoWhileExpr,
    EnumDecl,
    EnumPattern,
}

function createArgument(identifier: string, expr: Expr): Argument {
    return { identifier, expr, kind: SyntaxKind.Argument };
}

export interface Node {
    readonly kind: SyntaxKind;
}
export interface Expr extends Node {}
export interface TypeNode extends Node {
    typeParameterName: string; // todo: check
}
export interface Modifier extends Node {}
export interface Pattern extends Node {}
export interface Decl extends Node {
    annotations: Annotation[];
    genericConstraint: GenericConstraint[];
    genericParam: GenericParam;
    identifier: string;
    modifiers: Modifier[];
}

export interface Argument extends Node {
    readonly kind: SyntaxKind.Argument;
    expr: Expr;
    identifier: string;
    keyword?: string; // todo: inout
}

export interface Annotation extends Node {
    readonly kind: SyntaxKind.Annotation;
    arguments: Argument[];
    attributes?: string; // todo: @Attribute
    condition?: Expr; // todo: @When
    identifier: string;
}

export interface ArrayLiteral extends Expr {
    readonly kind: SyntaxKind.ArrayLiteral;
    elements: Expr[];
}

export interface AsExpr extends Expr {
    readonly kind: SyntaxKind.AsExpr;
    expr: Expr;
    shiftType: TypeNode;
}

export interface AssignExpr extends Expr {
    readonly kind: SyntaxKind.AssignExpr;
    leftExpr: Expr;
    rightExpr: Expr;
}

export interface BinaryExpr extends Expr {
    readonly kind: SyntaxKind.BinaryExpr;
    op: string; // todo: 
    leftExpr: Expr;
    rightExpr: Expr;
}

export interface Block extends Expr {
    readonly kind: SyntaxKind.Block;
    nodes: Node[];
}

export interface Body extends Node {
    readonly kind: SyntaxKind.Body;
    decls: Decl[];
}

/////////
export interface GenericConstraint extends Node {
    readonly kind: SyntaxKind.GenericConstraint;
    typeArgument: string;
    upperBounds: TypeNode[];
}

/////////////
export interface GenericParam extends Node {
    readonly kind: SyntaxKind.GenericParam;
    parameters: string[];
}

export interface CallExpr extends Expr {
    readonly kind: SyntaxKind.CallExpr;
    arguments: Argument[];
    callFunc: Expr;
}

export interface ClassDecl extends Decl {
    readonly kind: SyntaxKind.ClassDecl;
    body: Body;
    superTypes: TypeNode[];
}

export interface ConstPattern extends Pattern {
    readonly kind: SyntaxKind.ConstPattern;
    litConstExpr: LitConstExpr;
}

//////////////
export interface LitConstExpr extends Expr {
    readonly kind: SyntaxKind.LitConstExpr;
    literal: string;
}

export interface Constructor extends Node {
    readonly kind: SyntaxKind.Constructor;
    identifier: string;
    typeArguments: TypeNode[];
}

export interface DoWhileExpr extends Expr {
    readonly kind: SyntaxKind.DoWhileExpr;
    block: Block;
    condition: Expr;
}

export interface EnumDecl extends Decl {
    readonly kind: SyntaxKind.EnumDecl;
    constructors: Constructor[];
    decls: Decl[];
    superTypes: TypeNode[];
}

export interface EnumPattern extends Pattern {
    readonly kind: SyntaxKind.EnumPattern;
    constructor: Expr;
    patterns: Pattern[];
}

}